package net.neptech.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import net.neptech.api.SystemApi;
import net.neptech.dto.sys.StaffDTO;
import net.neptech.enums.workflow.InstanceConstant;
import net.neptech.enums.workflow.NodeUserTypeEnum;
import net.neptech.model.dto.*;
import net.neptech.model.workflow.InstanceRecord;
import net.neptech.model.workflow.Workflow;
import net.neptech.service.*;
import net.neptech.strategy.form.FormStrategyFactory;
import net.neptech.util.JsonUtil;
import net.neptech.utils.SecurityUtils;
import net.neptech.model.vo.DataQueryVO;
import net.neptech.model.vo.FormVO;
import net.neptech.model.vo.InstanceRecordVO;

import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author Saya
 * @Date 2025/8/20 11:43
 * @Description TODO
 **/
@Service
@RequiredArgsConstructor
public class InstanceServiceImpl implements InstanceService {
    private final SystemApi systemApi;
    private final InstanceRecordService instanceRecordService;
    private final InstanceOperRecordService instanceOperRecordService;
    private final WorkflowService workflowService;
    private final FlowableService flowableService;

    /**
     * 启动流程
     */
    @Override
    public String startInstance(InstanceParamDto instanceParamDto) {
        String uniqueId = instanceParamDto.getUniqueId();
        //业务key
        Workflow workflow = workflowService.getByUniqueId(uniqueId).get(0);
        if (workflow == null) {
            throw new RuntimeException("流程不存在");
        }
        if (workflow.getHidden() || workflow.getStop()) {
            throw new RuntimeException("流程被禁用");
        }
        if (!instanceParamDto.getFlowId().isBlank()) {
            if (!workflow.getFlowId().equals(instanceParamDto.getFlowId())) {
                throw new RuntimeException("流程不存在");
            }
        }
        instanceParamDto.setFlowId(workflow.getFlowId());
        String userId = SecurityUtils.getUserId().toString();
        StaffDTO staff = systemApi.getStaffByUserId(userId).getData();

        instanceParamDto.setStartUserId(String.valueOf(userId));
        Map<String, Object> paramMap = instanceParamDto.getParamMap();
        NodeUser rootUser = NodeUser.builder().userId(userId).name(staff.getStaffName()).type(NodeUserTypeEnum.USER.getKey()).build();
        paramMap.put(InstanceConstant.VariableKey.STARTER_USER, CollUtil.newArrayList(rootUser));

        instanceParamDto.setBizKey(workflow.getUniqueId());

        //判断字段格式
        String formItems = workflow.getFormConfig();
        List<FormVO> formItemVOS = JsonUtil.parseArray(formItems, FormVO.class);
        FormStrategyFactory.checkValue(formItemVOS, paramMap);
        String data = flowableService.start(instanceParamDto);
        instanceOperRecordService.saveStartProcessRecord(userId, data, instanceParamDto.getFlowId());
        return data;
    }


    /**
     * 查询已办任务的流程实例
     */
    @Override
    public PageResultDto<InstanceDto> queryMineDoneWorkflowInstance(DataQueryVO pageVO) {
        List<String> flowIdList = pageVO.getFlowIdList();
        if (CollUtil.isNotEmpty(flowIdList)) {
            flowIdList = workflowService.getAllRelatedFlowId(flowIdList);
        }
        QueryParamDto queryParamDto = BeanUtil.copyProperties(pageVO, QueryParamDto.class);
        queryParamDto.setAssign(SecurityUtils.getUserId());
        queryParamDto.setFlowIdList(flowIdList);
        PageResultDto<InstanceDto> pageResultDto = flowableService.queryCompletedInstance(queryParamDto);
        List<InstanceDto> records = pageResultDto.getRecords();
        if (records.isEmpty()) {
            return pageResultDto;
        }
        Set<String> instanceIdSet = records.stream().map(InstanceDto::getInstanceId).collect(Collectors.toSet());
        //流程实例记录
        List<InstanceRecord> instanceRecordList = instanceRecordService.getByInstanceIds(instanceIdSet);
        //发起人
        Set<String> startUserIdSet = instanceRecordList.stream().map(InstanceRecord::getUserId).collect(Collectors.toSet());
        List<StaffDTO> startUserList = new ArrayList<>();
        {
            for (String userId : startUserIdSet) {
                StaffDTO user = systemApi.getStaffByUserId(userId).getData();
                startUserList.add(user);
            }
        }
        for (InstanceDto record : records) {
            InstanceRecord instanceRecord = instanceRecordList.stream().filter(w -> StrUtil.equals(w.getId(), record.getInstanceId())).findAny().orElse(null);
            if (instanceRecord != null) {
                record.setName(instanceRecord.getName());
                StaffDTO startUser = startUserList.stream().filter(w -> w.getId().equals(instanceRecord.getUserId())).findAny().orElse(null);
                record.setGroupName(instanceRecord.getGroupName());
                if (startUser != null) {
                    record.setStartUserName(startUser.getStaffName());
                }
                record.setInstanceResult(instanceRecord.getResult());
                record.setInstanceStatus(instanceRecord.getStatus());
            }
        }
        return pageResultDto;
    }

    /**
     * 流程结束
     */
    @Override
    public void workflowEndEvent(InstanceParamDto instanceParamDto) {
        instanceRecordService.endProcess(instanceParamDto);
    }

    /**
     * 查询流程实例
     */
    @Override
    public Page queryList(DataQueryVO pageDto) {
        //查询所有的流程id
        List<String> allFlowIdList = new ArrayList<>();
        if (CollUtil.isNotEmpty(pageDto.getFlowIdList())) {
            List<String> data = workflowService.getAllRelatedFlowId(pageDto.getFlowIdList());
            allFlowIdList.addAll(data);
        }
        List<NodeUser> starterList = pageDto.getStarterList();
        List<String> startTime = pageDto.getStartTime();
        List<String> finishTime = pageDto.getFinishTime();
        Page<InstanceRecord> instanceRecordPage = instanceRecordService.lambdaQuery().in(CollUtil.isNotEmpty(allFlowIdList), InstanceRecord::getFlowId, allFlowIdList).eq(pageDto.getStatus() != null, InstanceRecord::getStatus, pageDto.getStatus()).ge(CollUtil.isNotEmpty(startTime) && startTime.size() >= 2, InstanceRecord::getCreateTime, (CollUtil.isNotEmpty(startTime) && startTime.size() >= 2) ? (DateUtil.parseDate(startTime.get(0))) : null).le(CollUtil.isNotEmpty(startTime) && startTime.size() >= 2, InstanceRecord::getCreateTime, (CollUtil.isNotEmpty(startTime) && startTime.size() >= 2) ? (DateUtil.endOfDay(DateUtil.parseDate(startTime.get(1)))) : null).ge(CollUtil.isNotEmpty(finishTime) && finishTime.size() >= 2, InstanceRecord::getEndTime, (CollUtil.isNotEmpty(finishTime) && finishTime.size() >= 2) ? (DateUtil.parseDate(finishTime.get(0))) : null).le(CollUtil.isNotEmpty(finishTime) && finishTime.size() >= 2, InstanceRecord::getEndTime, (CollUtil.isNotEmpty(finishTime) && finishTime.size() >= 2) ? (DateUtil.endOfDay(DateUtil.parseDate(finishTime.get(1)))) : null).in(CollUtil.isNotEmpty(starterList), InstanceRecord::getUserId, starterList == null ? new ArrayList<>() : starterList.stream().map(NodeUser::getUserId).collect(Collectors.toList())).eq(StrUtil.isNotBlank(pageDto.getProcessBizCode()), InstanceRecord::getProcessInstanceBizCode, pageDto.getProcessBizCode()).orderByDesc(InstanceRecord::getCreateTime).page(new Page<>(pageDto.getPageNum(), pageDto.getPageSize()));
        List<InstanceRecord> records = instanceRecordPage.getRecords();
        if (CollUtil.isEmpty(records)) {
            return instanceRecordPage;
        }
        //流程配置
        List<InstanceRecordVO> workflowInstanceRecordVOList = BeanUtil.copyToList(records, InstanceRecordVO.class);
        for (InstanceRecordVO record : workflowInstanceRecordVOList) {
            StaffDTO userDto = systemApi.getStaffByUserId(SecurityUtils.getUserId().toString()).getData();
            record.setFormData(null);
            record.setProcess(null);
            record.setRootUserAvatarUrl(userDto.getAvatar());
            record.setRootUserName(userDto.getStaffName());
        }
        Page<InstanceRecordVO> page = new Page<>();
        BeanUtil.copyProperties(instanceRecordPage, page);
        page.setRecords(workflowInstanceRecordVOList);
        return page;
    }

    /**
     * 查询流程实例详情
     */
    @Override
    public InstanceRecordVO queryDetailByWorkflowInstanceId(String workflowInstanceId) {
        InstanceRecord instanceRecord = instanceRecordService.lambdaQuery().eq(InstanceRecord::getId, workflowInstanceId).one();
        InstanceRecordVO record = BeanUtil.copyProperties(instanceRecord, InstanceRecordVO.class);
        //流程配置
        StaffDTO userDto = systemApi.getStaffByUserId(SecurityUtils.getUserId().toString()).getData();
        record.setFormData(null);
        record.setProcess(null);
        record.setRootUserAvatarUrl(userDto.getAvatar());
        record.setRootUserName(userDto.getStaffName());
        record.setCancelEnable(false);
        return record;
    }

    /**
     * 查询处理中的任务
     */
    @Override
    public List<TaskDto> queryTaskListInProgress(String instanceId) {
        TaskParamDto variableQueryParamDto = new TaskParamDto();
        variableQueryParamDto.setProcessInstanceId(instanceId);
        List<TaskDto> taskDtoList = flowableService.queryTaskAssignee(variableQueryParamDto);
        for (TaskDto taskDto : taskDtoList) {
            StaffDTO userDto = systemApi.getStaffByUserId(taskDto.getAssign()).getData();
            taskDto.setUserName(userDto.getStaffName());
        }
        return taskDtoList;
    }
}
